const http = require('http')
const path = require('path')
const fse = require('fs-extra')
const multiparty = require('multiparty')
const server = http.createServer()

const UPLOAD_DIR = path.resolve(__dirname, 'target') // 大文件存储目录

const resolvePost = (req) => {
  return new Promise((resolve) => {
    let chunk = ''
    req.on('data', (data) => {
      chunk += data
    })
    req.on('end', () => {
      resolve(JSON.parse(chunk))
    })
  })
}

const pipeStream = (path, writeStream) => {
  return new Promise((resolve) => {
    const readStream = fse.createReadStream(path)
    readStream.on('end', () => {
      fse.unlinkSync(path)
      resolve()
    })
    readStream.pipe(writeStream)
  })
}

const mergeFileChunk = async (filePath, filename, size) => {
  const chunkDir = path.resolve(UPLOAD_DIR, filename)
  const chunkPaths = await fse.readdir(chunkDir)
  // 根据切片下标进行排序
  // 否则直接读取目录获得的顺序可能会错乱
  chunkPaths.sort((a, b) => a.split('-')[1] - b.split('-')[1])
  await Promise.all(
    chunkPaths.map((chunkPath, index) => {
      return pipeStream(
        path.resolve(chunkDir, chunkPath),
        fse.createWriteStream(filePath, {
          start: index * size,
          end: (index + 1) * size,
        })
      )
    })
  )
  // 合并后删除切片的目录
  fse.rmdirSync(chunkDir)
}

server.on('request', async (req, res) => {
  if (req.url === '/api/upload') {
    const multipart = new multiparty.Form()
    multipart.parse(req, async (err, fields, files) => {
      if (err) {
        return
      }
      // console.log(files) // { chunk: [file] }
      // console.log(fields) // { hash: [ '管平湖 - 广陵散.mp3-4' ], filename: [ '管平湖 - 广陵散.mp3' ] }
      const [chunk] = files.chunk
      const [hash] = fields.hash
      const [filename] = fields.filename
      const chunkDir = path.resolve(UPLOAD_DIR, filename)
      // 切片目录不存在，创建切片目录
      if (!fse.existsSync(chunkDir)) {
        await fse.mkdir(chunkDir)
      }
      await fse.move(chunk.path, `${chunkDir}/${hash}`)
      res.end('received file chunk')
    })
  } else if (req.url === '/api/merge') {
    const data = await resolvePost(req)
    const { filename, size } = data
    const filePath = path.resolve(UPLOAD_DIR, `${filename}`)
    await mergeFileChunk(filePath, filename, size)
    res.end(
      JSON.stringify({
        code: 0,
        message: 'file merged success',
      })
    )
  }
})

server.listen(5000, () => console.log('服务器地址 http://localhost:5000'))
